package rest

import (
	"errors"
	"fmt"
	"os"

	"gitee.com/youkelike/ziam/zerrors"
	"gitee.com/youkelike/zlog"
)

var (
	ErrEmptyServer = errors.New("server has no server defined")
)

type errConfigurationInvalid []error

var (
	_ error             = errConfigurationInvalid{}
	_ zerrors.Aggregate = errConfigurationInvalid{}
)

func newErrConfigurationInvalid(errs []error) error {
	switch len(errs) {
	case 0:
		return nil
	default:
		return errConfigurationInvalid(errs)
	}
}

func (e errConfigurationInvalid) Error() string {
	return fmt.Sprintf("invalid configuration: %v", zerrors.NewAggregate(e).Error())
}

func (e errConfigurationInvalid) Errors() []error {
	return e
}

func (e errConfigurationInvalid) Is(target error) bool {
	return e.Visit(func(err error) bool {
		return errors.Is(err, target)
	})
}

func (e errConfigurationInvalid) Visit(f func(err error) bool) bool {
	for _, i := range e {
		switch err := i.(type) {
		case errConfigurationInvalid:
			return err.Visit(f)
		case zerrors.Aggregate:
			for _, j := range err.Errors() {
				return f(j)
			}
		default:
			return f(err)
		}
	}
	return false
}

func validateConfig(c *Config) []error {
	validationErrors := make([]error, 0)

	if c.GroupVersion == nil || len(c.GroupVersion.Group) == 0 || len(c.GroupVersion.Version) == 0 {
		validationErrors = append(validationErrors,
			fmt.Errorf("GroupVersion is required when initializing a RESTClient"))
		return validationErrors
	}

	// authz 必须要有 secretID 和 secretKey，
	// apiserver 必须要有 bearerToken
	if c.GroupVersion.Group == "authz" && (len(c.SecretID) == 0 || len(c.SecretKey) == 0) {
		validationErrors = append(validationErrors,
			fmt.Errorf("secretID and secretKey are need for group authz"))
		zlog.Infow("====", zlog.Any("config", c))
		return validationErrors
	} else if c.GroupVersion.Group == "apiserver" && len(c.BearerToken) == 0 {
		validationErrors = append(validationErrors,
			fmt.Errorf("bearerToken is need for group apiserver"))
		return validationErrors
	}

	// methods := make([]string, 0, 3)
	// if len(c.BearerToken) != 0 {
	// 	methods = append(methods, "token")
	// }
	// if len(c.Username) != 0 || len(c.Password) != 0 {
	// 	methods = append(methods, "basicAuth")
	// }
	// if len(c.SecretID) != 0 || len(c.SecretKey) != 0 {
	// 	methods = append(methods, "secretAuth")
	// }
	// // 只能有一种认证方式
	// if len(methods) > 1 {
	// 	validationErrors = append(validationErrors,
	// 		fmt.Errorf("more than one authentication method found; found %v, only one is allowed", methods))
	// }

	if c.Insecure {
		return validationErrors
	}

	// 秘钥文件必须提供
	if len(c.KeyFile) == 0 {
		validationErrors = append(validationErrors,
			fmt.Errorf("keyFile must be specified to use the clientCert authentication method"))
	} else {
		// 检查秘钥文件是否能正常读取
		clientKeyFile, err := os.Open(c.KeyFile)
		if err != nil {
			validationErrors = append(validationErrors,
				fmt.Errorf("unable to read client KeyFile %v due to %v", c.KeyFile, err))
		} else {
			defer clientKeyFile.Close()
		}
	}

	// CA 文件必须提供
	if len(c.CAFile) == 0 {
		validationErrors = append(validationErrors,
			fmt.Errorf("CaFile must be specified to use the clientCert authentication method"))
	} else {
		// 检查 CA 文件是否能正常读取
		clientCertCA, err := os.Open(c.CAFile)
		if err != nil {
			validationErrors = append(validationErrors,
				fmt.Errorf("unable to read CaFile %v due to %v", c.CAFile, err))
		} else {
			defer clientCertCA.Close()
		}
	}

	// 证书文件必须提供
	if len(c.CertFile) == 0 {
		validationErrors = append(validationErrors,
			fmt.Errorf("CertFile must be specified to use the clientCert authentication method"))
	} else {
		// 检查证书文件是否能正常读取
		clientCertFile, err := os.Open(c.CertFile)
		if err != nil {
			validationErrors = append(validationErrors,
				fmt.Errorf("unable to read client CertFile %v due to %v", c.CertFile, err))
		} else {
			defer clientCertFile.Close()
		}
	}

	return validationErrors
}
